﻿using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace GitTool
{
    public class GitTool
    {
        public static LogTool.Callback Call = null;

        # region Git目录解析上传

        /// <summary>
        /// 载入Git路径下的配置信息，并上传当前git
        /// </summary>
        public static void upLoadGitDir(string Dir)
        {
            if (!isGitDir(Dir)) return;

            if(Dir.EndsWith("\\")) Dir = Dir.Substring(0, Dir.Length-1);
            string configPath =  Dir + "\\.git\\config";
            if (File.Exists(configPath))
            {
                getConfigSettings(configPath);  // 获取config文件的配置信息
                RegistryTool.save("localDir", Directory.GetParent(Dir));    // 获取dir的父目录

                loadSettings();                 // 载入注册表配置
                GitTool.Upload(true, true);     // 上传更新至Git
            }
        }

        /// <summary>
        /// 载入config文件中的配置信息，记录到注册表中
        /// </summary>
        private static void getConfigSettings(string configPath)
        {
            string data = MD5_Tool.fileToString(configPath, Encoding.UTF8);
            string[] lines = data.Replace("\r\n", "\n").Split('\n');
            foreach (string line0 in lines)
            {
                string line = line0.Trim();
                if (line.Equals("")) continue;

                if (line.StartsWith("url = ")) RegistryTool.save("gitUrl", line.Substring("url = ".Length));
                else if (line.StartsWith("name = ")) RegistryTool.save("UserName", line.Substring("name = ".Length));
                else if (line.StartsWith("email = ")) RegistryTool.save("userEmail", line.Substring("email = ".Length));
            }
        }

        /// <summary>
        /// 判断是否为Git目录
        /// </summary>
        private static bool isGitDir(string GitDir)
        {
            if(GitDir.EndsWith("\\")) GitDir = GitDir.Substring(0, GitDir.Length-1);
            return (Directory.Exists(GitDir) && Directory.Exists(GitDir + "\\.git"));
        }
        # endregion

        # region git注册表配置信息

        public static string userName = "";         // 用户名
        public static string userEmail = "";        // 邮箱
        public static string userPassword = "";     // 密码
        public static string gitUrl = "";           // https://git.oschina.net/joymeng/empty.git
        public static string localDir = "";         // 本地路径
        public static string gitEXE = "";           // C:\Program Files (x86)\Git\cmd\git.exe

        /// <summary>
        /// 载入配置信息
        /// </summary>
        public static void loadSettings()
        {
            GitTool.userName = RegistryTool.read("UserName");
            GitTool.userEmail = RegistryTool.read("userEmail");
            GitTool.userPassword = RegistryTool.read("userPassword");
            GitTool.gitUrl = RegistryTool.read("gitUrl");
            GitTool.localDir = RegistryTool.read("localDir");
            if (GitTool.localDir.Equals("")) GitTool.localDir = AppDomain.CurrentDomain.BaseDirectory + "GitDir";

            GitTool.gitEXE = RegistryTool.read("gitEXE");
            if (GitTool.gitEXE.Equals("")) GitTool.gitEXE = getGitPath("C:\\", true);
        }
    
        /// <summary>
        /// 自动检测C盘获取git.exe文件所在路径
        /// </summary>
        private static string getGitPath(string Dir = null, bool defaultCheck = false)
        {
            if (defaultCheck)
            {
                string path = @"C:\Program Files (x86)\Git\cmd\git.exe";
                if (File.Exists(path)) return path;
            
                path = @"C:\Program Files\Git\cmd\git.exe";
                if (File.Exists(path)) return path;
            }

            if (Directory.Exists(Dir))
            {
                //所有子文件名
                string[] files = System.IO.Directory.GetFiles(Dir);
                foreach (string file in files)
                {
                    String name = System.IO.Path.GetFileName(file);
                    if (name.Equals("git.exe")) return file;
                }

                //所有子目录名
                string[] Dirs = System.IO.Directory.GetDirectories(Dir);
                foreach (string dir in Dirs)
                {
                    try
                    {
                        string path = getGitPath(dir);                          //子目录下所有子文件名
                        if (!path.Equals("") && File.Exists(path)) return path;
                    }
                    catch (Exception) { }
                }
            }

            return "";
        }
        #endregion

        # region git库相关操作逻辑
        //set git="C:\Program Files (x86)\Git\cmd\git.exe"
        //cd D:\sci\Visual Studio 2008\Projects\GitTool\GitTool\bin\Debug\GitDir
        //%git% clone https://git.oschina.net/joymeng/empty.git
        //pause

        /// <summary>
        /// 下载git库
        /// </summary>
        public static void Download(LogTool.Callback Call = null)
        {
            if (File.Exists(gitEXE))
            {
                WorkingDirectory = localDir;
                string projectName = getProjectName(gitUrl);

                if (!Directory.Exists(WorkingDirectory) || !Directory.Exists(WorkingDirectory + "\\" + projectName))
                {
                    Directory.CreateDirectory(WorkingDirectory);
                    Git("clone " + gitUrl);                // 下载git库
                }
                else
                {
                    WorkingDirectory = localDir + "\\" + projectName;
                    Git("pull " + gitUrl);                 // 更新
                }
            }
        }

        //set git="C:\Program Files (x86)\Git\cmd\git.exe"
        //cd D:\sci\Visual Studio 2008\Projects\GitTool\GitTool\bin\Debug\GitDir\empty

        //%git% add -A
        //%git% commit -m 2017_08_14
        //%git% pull https://git.oschina.net/joymeng/empty.git
        //%git% push https://joyXXX:joyXXX@git.oschina.net/joymeng/empty.git
        //pause

        /// <summary>
        /// 上传git库
        /// </summary>
        public static void Upload(bool genMD5 = false, bool genFileHtml = false)
        {
            if (File.Exists(gitEXE))
            {
                if (!Directory.Exists(WorkingDirectory)) Download();// 若本地git库不存在，则下载

                string projectName = getProjectName(gitUrl);        // 获取git库名称
                WorkingDirectory = localDir + "\\" + projectName;   // 设置本地路径

                if (genFileHtml) MD5_Tool.GenGitFileHtml(WorkingDirectory, gitUrl);// 生成文件列表信息
                if (genMD5) MD5_Tool.GenGitMD5(WorkingDirectory, gitUrl);          // 生成文件MD5信息
                if (Directory.Exists(WorkingDirectory))
                {
                    Git("config user.name " + userName);   // 设置用户名
                    Git("config user.email " + userEmail); // 设置Email
                    
                    Git("add -A");                         // 添加所有文件变动
                    Git("commit -m " + DateTime.Now.ToString("yyyy-MM-dd_HH.mm.ss"));  // 本地修改、添加注释

                    Git("pull " + gitUrl);                 // 获取最新的库信息
                    string pushUrl = gitUrl.Replace("https://", "https://" + userName + ":" + userPassword + "@");
                    Git("push " + pushUrl);                // 更新至git库
                }
            }
        }

        //public static void test()
        //{
        //    string projectName = getProjectName(gitUrl);        // 获取git库名称
        //    WorkingDirectory = localDir + "\\" + projectName;   // 设置本地路径
        //    string pushUrl = gitUrl.Replace("https://", "https://" + userName + ":" + userPassword + "@");
        //    Git("push " + pushUrl);                // 更新至git库
        //}

        /// <summary>
        /// 通过cmd执行git命令
        /// </summary>
        public static string Git(string cmd)
        {
            if (File.Exists(gitEXE))
            {
                string GitEXE = "\"" + gitEXE + "\"";
                string result = Run(GitEXE + " " + cmd);
                result = trimResult(result);

                if (Call != null) Call(result);
                return result;
            }
            return "";
        }

        //Microsoft Windows [版本 6.1.7601]
        //版权所有 (c) 2009 Microsoft Corporation。保留所有权利。

        //D:\sci\Visual Studio 2008\Projects\GitTool\GitTool\bin\Debug\GitDir>"C:\Program Files (x86)\Git\cmd\git.exe" clone https://git.oschina.net/scimence/GitTool.git

        //D:\sci\Visual Studio 2008\Projects\GitTool\GitTool\bin\Debug\GitDir>exit
        
        /// <summary>
        /// 提取有效输出信息
        /// </summary>
        private static string trimResult(string result)
        {
            StringBuilder Str = new StringBuilder();
            string[] lines = result.Replace("\r\n", "\n").Split('\n');
            for (int i = 3; i < lines.Length - 3; i++)
                Str.AppendLine(lines[i]);
            return Str.ToString();
        }

        /// <summary>
        /// 执行CMD命令
        /// </summary>
        private static string Run(string cmd)
        {
            Process P = newProcess("cmd.exe");
            P.StandardInput.WriteLine(cmd);
            P.StandardInput.WriteLine("exit");
            string outStr = P.StandardOutput.ReadToEnd();
            P.Close();
            return outStr;
        }

        private static string WorkingDirectory = "";
        /// <summary>
        /// 以后台进程的形式执行应用程序（d:\*.exe）
        /// </summary>
        private static Process newProcess(String exe)
        {
            Process P = new Process();
            P.StartInfo.CreateNoWindow = true;
            P.StartInfo.FileName = exe;
            P.StartInfo.UseShellExecute = false;
            P.StartInfo.RedirectStandardError = true;
            P.StartInfo.RedirectStandardInput = true;
            P.StartInfo.RedirectStandardOutput = true;
            //P.StartInfo.WorkingDirectory = @"C:\windows\system32";
            if (!WorkingDirectory.Equals("")) P.StartInfo.WorkingDirectory = WorkingDirectory;
            P.Start();
            return P;
        }

        /// <summary>
        /// 获取gitUrl对应的库名称
        /// </summary>
        public static string getProjectName(string gitUrl)
        {
            string Name = "";

            int start = gitUrl.LastIndexOf("/") + 1;
            int end = gitUrl.LastIndexOf(".git");
            if (end != -1) Name = gitUrl.Substring(start, end - start);
            else Name = gitUrl.Substring(start);

            return Name;
        }

        private string ToLinux(string path)
        {
            return path.Replace('\\', '/');
        }

        # endregion

    }
}
